package org.red5.server.net.rtmp.codec;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.codec.binary.Hex;
import org.apache.mina.core.buffer.IoBuffer;
import org.junit.Test;
import org.red5.io.amf.Output;
import org.red5.io.utils.IOUtils;
import org.red5.server.api.Red5;
import org.red5.server.net.rtmp.IRTMPHandler;
import org.red5.server.net.rtmp.RTMPConnection;
import org.red5.server.net.rtmp.RTMPMinaConnection;
import org.red5.server.net.rtmp.RTMPUtils;
import org.red5.server.net.rtmp.event.Invoke;
import org.red5.server.net.rtmp.message.ChunkHeader;
import org.red5.server.net.rtmp.message.Header;
import org.red5.server.net.rtmp.message.Packet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestRTMPProtocolDecoder implements IRTMPHandler {

    protected Logger log = LoggerFactory.getLogger(TestRTMPProtocolDecoder.class);

    @Test
    public void testDecodeChannelId() {
        {
            IoBuffer p00 = IoBuffer.wrap(IOUtils.hexStringToByteArray("03"));
            ChunkHeader chh = ChunkHeader.read(p00);
            assertEquals(3, chh.getChannelId());
        }
        {
            IoBuffer p00 = IoBuffer.wrap(IOUtils.hexStringToByteArray("43"));
            ChunkHeader chh = ChunkHeader.read(p00);
            assertEquals(3, chh.getChannelId());
        }
        for (int i = 2; i < 64 * 1024; ++i) {
            IoBuffer b = IoBuffer.allocate(3);
            RTMPUtils.encodeHeaderByte(b, (byte) (i < 64 ? 0 : (i > 63 && i < 320 ? 1 : 2)), i);
            b.flip();
            ChunkHeader chh = ChunkHeader.read(b);
            assertEquals(i, chh.getChannelId());
        }
    }

    @Test
    public void testDecodeBufferPro() {
        log.debug("\ntestDecodeBufferPro");
        RTMPProtocolDecoder dec = new RTMPProtocolDecoder();
        RTMPConnection conn = new RTMPMinaConnection();
        conn.getState().setState(RTMP.STATE_CONNECTED);
        conn.setHandler(this);
        // pro clustered packet with buffer underun
        IoBuffer p1 = IoBuffer.wrap(IOUtils.hexStringToByteArray(
                "c5f3d6fefffe7d4545f9bd27f9e839127a03d2671bc2990c253435c8fed5741eff367cd667f71cdc50aef2cc666d5a97f5517e008fef2fd806e406281e0a14a495c5c5efaaac5e208e211618230020175af0cddddcbf4d3babaf46be51856ef7f7dff857bbdf5f6fd822d12f7ae65d49d2eac78232ef7eb11b277e5414f77fdfbb9f05447fbefbfdaefc23f21f9bf84884fc617fce295febc791d627ec0f0382704ca28db10fa62aefb0b82009413e2ae566bbe6ffff6347961a9efd5725570dccce6220a25c5715c4605b10605bd815b82b0806710b1717ddbfe2014931b4cfb07670740410ae061f7953bd9374d6dffc0acefe3759669fa7cd211d513f92f0a6eed6667d90ca0721c6bbd47787bf8af06b0a0ef5baef10e5c562b1c63876017c018d82bbbedcaca8bc5d65983eba744b4a6c83abe0aed1ae6c9d49c60aedb71b5d17afaf45f309df1cc8128e71f60cddf65146efbfc59f77dfbf17e111030cb47aef7cbfc64297def7b979e3c2ae2f7ac9e48884d817a144696c438dce160b9bb9227bca26b6d9b8f9d7ad5e6a1b26ea4b528fe9e912d7993a7fb012203c81842c3ed80ecb65563289f67bd4974fb7427a13df261657cc67ebf9d71d8ad34da1d5b7daa9b278d4269b6d97e9d8053404b81f0100d96e5b7887ab7e74b37db5103e3169edfcd5a7ffb4caa952bcc626438ac5c3a53723eee62665631d82531a08025eda7f504cb58bc535ec9f92110a900bc09f6c567e0d1e9afa16dce582c2d2e9f5fbe0a64cebaafef9bd78809d575ac66c51ef777bd40bf20b33bef7f20c57778adefdfead5fc9f2fc25a7e9f385414b7bddfbec660ffd9ff7b6cd92fa89e1d607a9d55577fe1108938509b7cd5a3b700d2ae9b1859cb63aa67f0e95bcbd72c041f54d76026c0a586c5e11949488f275fc6cb7d8448d047c193a4733e4dc0e5f1cdce07f8c085ec57bb65b72dbb624e09f2f9b3f9a871161d0881352a190eacaac40974e64bee0948d4c807a4f3233dbfe24225f873d73c015d2fa817e221a7875e74ef7e65ffea9e38acbbf35f10b0ab82115dce043cebf9a10bc61c358f51d84f4153b4a99ffd5d8eeaf98d3fbcdfffef36f1bb97bb38ae5e28dddc2ad1dc12ddd3f9a900ffee85de56fca6ceffaa88fd7bfd7476e119b5f863ed6f5c8ab904a172e8defca1033f7777ddfc42deeeff17dfdfc5f7efe41aafbfbbbbbebb7f570a377bbbbee0ecc7c9e59a7b7a4c00e4caa2572427afaaaa7a0ec1dfeabdc33e0294097b7d34eca320cc77bad6d3562ba14820203e258cfc3b59571fc75f2dbbfd008c015228190d10cf72fcb9a796dcf8fa8379bb9bfe1086c6e16cb42ab810b53dfed8c485438561c2c49234ad93d068aca3075f79b8ab2fb7cac9c7c47cd10440e0c79da5769373c6661b98cd339d876b051bb8c458c3234160cb7c7d7c52c18acf07f5fb1652436130472fb64ed4059e8f7fb3dfd6d036c121b00aaa58be7b66d31ff27c3c0a03e13201883e141d00ed23c61dfe981de53f2c31437c592fd98ad45e90c4058a605d75346348494b61d44ac9eb19b9e586c6ecb67f1b227352ecc4cdd76fb508c64bd74b6c9eb07fcb657e0b79b9683abc9e3b9809e1606c0a5e2b3336f7bf2f7c5f091755afe64bd727afb755fa5d157209bdfc61aefeefbeefe1327777f718f77efbef7b704f047eedb0531d085453517555bef9a2d6fdbe488b1d8f7f4c65ffc5e24fe94de949e08e10106428407d85c71f11c26946c0c0613b2ee72b74fb7cc0a8692d60c48e16648383c6121324fb7d7dd014c2b94aba95aa56dc9fe4f90202c1b0130a50a46aec45b6a3bbcf4af9546b08c298cff07ddbba1dcc13b86cb1f1473a7b08977f5593e4f9309bb089ad8dafc2c3916ebaae4f16c11071ac28c4f97d5253815ef7c1effacd6a5b87b3133d88687e7acfc1a48a808db125623cf9c9bc8d198f160b6b17f99a28f6fb7afcacc607fd1990688f6abb69b1a1675e72d094407824223871cd42a1a5ba606663cba0eb4661d795950004e9540c21c06e18ca820be5b06dc6b393aeca7791bd807fc55fe40e820e00bd87aa324f7359424ab72be9ebb7fa141d650a0eca665f8e8598a62862988e3e2586e53214af4e3bb305b4c8be9da0bd7421a6e0d451cc3722fd3c1de044d7ff63514f82c19cf2c658cf3c4bd662d91fd0cf7c75871e5ad7e4f28144280b8852081bbd4e9a42ee5e5a36c1b06caf92b251498ebf8402c0ade4ffbe3b924ad76d972b6bd7697f90affc1713b7afbe9f44dcc27a7e11117efdff2dff204adbdf3b1a20350441f040ba67ed0ad201edb52333105d0212c6c91a087fd3a0580fc1a8300a216c48f1acf6377a756cdc925e7195be25f4fa1471811185ef0d7090e6b69dfefb023905881aa2f6e7877e1de48878dd4a76a7f4fe4f6424a110d146addf7d8457ec6cb31c37a197dff4f98d01156b4ae88facff4e459aa594560594b7526fcb9620e5cf172f37aeb5b42c18813c29f527381f76675860e4bbfa45068158145b18f7dbf45bfb43a78de2b15f5f508e560bee5c69feace4f122e89191a867064fa8af59bace70b1958b53325b4f87fbd97852e91f923d247db70bcb7db49d43e7b6e069c3d11c8362039d0d57aaa7fe4f161f02f44858b082228e5620633ec4f67f0523d8d8c9d88a77a840a0b1878cc79ebe2dd3e878d6828aec32e4f8ca928f050635acbd3bdd4ec92ab40760b1582b3f5cfaac31d8e4366e54d1831893d96bf650d82d0a850642ad04b987465c0fd7cfa3f258070705f96661b9c593c168134100904c14301583c5735d17f8d3d5a93ff4ffcd3848119d26737ff1613182b784a7d8d9979be8a7cac128e2cf1c2b3d2cb2145971e79e9e235ca5d6bc5992f15114fbe4d3fc413bdef9bc013e0e67960c6a6b45a47ab6e59ab7ce1f5063c9f61aaf04cba22f5e5d8c817db92117e87c6e7815598318368cf84e1fbfdf52c7bc7896a7bcebec157523664991652649e30c0898601c11850dc4ce4fa81052edfd1cac954a54a50176d5e2eb53280cc232b656d5098d12f77dfd7be459fdbe44095071e2ee3cf6c38ffafc739ed0ef4fd47a9b20c4259790540b8cf56647f85129326e1ee163efc4b5b976fb7c7b6c1ebede763d2d04abdc1530e0b8c47633c3df7ded7ef83690c30e49b8c65efaad7244531bf7eeb96fc7164f2b244434c7d8627289e90952997dc05425152826add28206b553895e82583df63dfd10c98943a798eff3858958e784423ab971b84ec17453e09473d5dff771c8a8a26c578a7fd95df276b58aff4763a5a99aa8c28af21be091776cbcc88608898567e62ef3774b58f611d725a5bb85f6973b5bdbaf61543034311efafcfd20df4b8bb4dba527c4608871c4958f44e513e9f45ef97bd7104be7d5f493eaca085d2fab995fa30a48627771ea3e23112e11f73163dbe4f120868f1efb7f154fdf08ebd13b52e826ba4d3fe52a2fbf13e586845f5fb7ea63f72d4cd97f05a825492fbfeae46bf2b64be27b7ad7237e13bfbf8848bf77c9be4108e5c2f66daee21dfbbc3bca5be0aaf5a808a8006ffffff0001380801000000010e31"));
        List<Object> objs = dec.decodeBuffer(conn, p1);
        log.debug("Objects #0: {}", objs);
        // edge02
        IoBuffer p2 = IoBuffer.wrap(IOUtils.hexStringToByteArray(
                "c5f3d6fefffe7d4545f9bd27f9e839127a03d2671bc2990c253435c8fed5741eff367cd667f71cdc50aef2cc666d5a97f5517e008fef2fd806e406281e0a14a495c5c5efaaac5e208e211618230020175af0cddddcbf4d3babaf46be51856ef7f7dff857bbdf5f6fd822d12f7ae65d49d2eac78232ef7eb11b277e5414f77fdfbb9f05447fbefbfdaefc23f21f9bf84884fc617fce295febc791d627ec0f0382704ca28db10fa62aefb0b82009413e2ae566bbe6ffff6347961a9efd5725570dccce6220a25c5715c4605b10605bd815b82b0806710b1717ddbfe2014931b4cfb07670740410ae061f7953bd9374d6dffc0acefe3759669fa7cd211d513f92f0a6eed6667d90ca0721c6bbd47787bf8af06b0a0ef5baef10e5c562b1c63876017c018d82bbbedcaca8bc5d65983eba744b4a6c83abe0aed1ae6c9d49c60aedb71b5d17afaf45f309df1cc8128e71f60cddf65146efbfc59f77dfbf17e111030cb47aef7cbfc64297def7b979e3c2ae2f7ac9e48884d817a144696c438dce160b9bb9227bca26b6d9b8f9d7ad5e6a1b26ea4b528fe9e912d7993a7fb012203c81842c3ed80ecb65563289f67bd4974fb7427a13df261657cc67ebf9d71d8ad34da1d5b7daa9b278d4269b6d97e9d8053404b81f0100d96e5b7887ab7e74b37db5103e3169edfcd5a7ffb4caa952bcc626438ac5c3a53723eee62665631d82531a08025eda7f504cb58bc535ec9f92110a900bc09f6c567e0d1e9afa16dce582c2d2e9f5fbe0a64cebaafef9bd78809d575ac66c51ef777bd40bf20b33bef7f20c57778adefdfead5fc9f2fc25a7e9f385414b7bddfbec660ffd9ff7b6cd92fa89e1d607a9d55577fe1108938509b7cd5a3b700d2ae9b1859cb63aa67f0e95bcbd72c041f54d76026c0a586c5e11949488f275fc6cb7d8448d047c193a4733e4dc0e5f1cdce07f8c085ec57bb65b72dbb624e09f2f9b3f9a871161d0881352a190eacaac40974e64bee0948d4c807a4f3233dbfe24225f873d73c015d2fa817e221a7875e74ef7e65ffea9e38acbbf35f10b0ab82115dce043cebf9a10bc61c358f51d84f4153b4a99ffd5d8eeaf98d3fbcdfffef36f1bb97bb38ae5e28dddc2ad1dc12ddd3f9a900ffee85de56fca6ceffaa88fd7bfd7476e119b5f863ed6f5c8ab904a172e8defca1033f7777ddfc42deeeff17dfdfc5f7efe41aafbfbbbbbebb7f570a377bbbbee0ecc7c9e59a7b7a4c00e4caa2572427afaaaa7a0ec1dfeabdc33e0294097b7d34eca320cc77bad6d3562ba14820203e258cfc3b59571fc75f2dbbfd008c015228190d10cf72fcb9a796dcf8fa8379bb9bfe1086c6e16cb42ab810b53dfed8c485438561c2c49234ad93d068aca3075f79b8ab2fb7cac9c7c47cd10440e0c79da5769373c6661b98cd339d876b051bb8c458c3234160cb7c7d7c52c18acf07f5fb1652436130472fb64ed4059e8f7fb3dfd6d036c121b00aaa58be7b66d31ff27c3c0a03e13201883e141d00ed23c61dfe981de53f2c31437c592fd98ad45e90c4058a605d75346348494b61d44ac9eb19b9e586c6ecb67f1b227352ecc4cdd76fb508c64bd74b6c9eb07fcb657e0b79b9683abc9e3b9809e1606c0a5e2b3336f7bf2f7c5f091755afe64bd727afb755fa5d157209bdfc61aefeefbeefe1327777f718f77efbef7b704f047eedb0531d085453517555bef9a2d6fdbe488b1d8f7f4c65ffc5e24fe94de949e08e10106428407d85c71f11c26946c0c0613b2ee72b74fb7cc0a8692d60c48e16648383c6121324fb7d7dd014c2b94aba95aa56dc9fe4f90202c1b0130a50a46aec45b6a3bbcf4af9546b08c298cff07ddbba1dcc13b86cb1f1473a7b08977f5593e4f9309bb089ad8dafc2c3916ebaae4f16c11071ac28c4f97d5253815ef7c1effacd6a5b87b3133d88687e7acfc1a48a808db125623cf9c9bc8d198f160b6b17f99a28f6fb7afcacc607fd1990688f6abb69b1a1675e72d094407824223871cd42a1a5ba606663cba0eb4661d795950004e9540c21c06e18ca820be5b06dc6b393aeca7791bd807fc55fe40e820e00bd87aa324f7359424ab72be9ebb7fa141d650a0eca665f8e8598a62862988e3e2586e53214af4e3bb305b4c8be9da0bd7421a6e0d451cc3722fd3c1de044d7ff63514f82c19cf2c658cf3c4bd662d91fd0cf7c75871e5ad7e4f28144280b8852081bbd4e9a42ee5e5a36c1b06caf92b251498ebf8402c0ade4ffbe3b924ad76d972b6bd7697f90affc1713b7afbe9f44dcc27a7e11117efdff2dff204adbdf3b1a20350441f040ba67ed0ad201edb52333105d0212c6c91a087fd3a0580fc1a8300a216c48f1acf6377a756cdc925e7195be25f4fa1471811185ef0d7090e6b69dfefb023905881aa2f6e7877e1de48878dd4a76a7f4fe4f6424a110d146addf7d8457ec6cb31c37a197dff4f98d01156b4ae88facff4e459aa594560594b7526fcb9620e5cf172f37aeb5b42c18813c29f527381f76675860e4bbfa45068158145b18f7dbf45bfb43a78de2b15f5f508e560bee5c69feace4f122e89191a867064fa8af59bace70b1958b53325b4f87fbd97852e91f923d247db70bcb7db49d43e7b6e069c3d11c8362039d0d57aaa7fe4f161f02f44858b082228e5620633ec4f67f0523d8d8c9d88a77a840a0b1878cc79ebe2dd3e878d6828aec32e4f8ca928f050635acbd3bdd4ec92ab40760b1582b3f5cfaac31d8e4366e54d1831893d96bf650d82d0a850642ad04b987465c0fd7cfa3f258070705f96661b9c593c168134100904c14301583c5735d17f8d3d5a93ff4ffcd3848119d26737ff1613182b784a7d8d9979be8a7cac128e2cf1c2b3d2cb2145971e79e9e235ca5d6bc5992f15114fbe4d3fc413bdef9bc013e0e67960c6a6b45a47ab6e59ab7ce1f5063c9f61aaf04cba22f5e5d8c817db92117e87c6e7815598318368cf84e1fbfdf52c7bc7896a7bcebec157523664991652649e30c0898601c11850dc4ce4fa81052edfd1cac954a54a50176d5e2eb53280cc232b656d5098d12f77dfd7be459fdbe44095071e2ee3cf6c38ffafc739ed0ef4fd47a9b20c4259790540b8cf56647f85129326e1ee163efc4b5b976fb7c7b6c1ebede763d2d04abdc1530e0b8c47633c3df7ded7ef83690c30e49b8c65efaad7244531bf7eeb96fc7164f2b244434c7d8627289e90952997dc05425152826add28206b553895e82583df63dfd10c98943a798eff3858958e784423ab971b84ec17453e09473d5dff771c8a8a26c578a7fd95df276b58aff4763a5a99aa8c28af21be091776cbcc88608898567e62ef3774b58f611d725a5bb85f6973b5bdbaf61543034311efafcfd20df4b8bb4dba527c4608871c4958f44e513e9f45ef97bd7104be7d5f493eaca085d2fab995fa30a48627771ea3e23112e11f73163dbe4f120868f1efb7f154fdf08ebd13b52e826ba4d3fe52a2fbf13e586845f5fb7ea63f72d4cd97f05a825492fbfeae46bf2b64be27b7ad7237e13bfbf8848bf77c9be4108e5c2f66daee21dfbbc3bca5be0aaf5a808a8006ffffff0001380801000000010e26"));
        List<Object> objs2 = dec.decodeBuffer(conn, p2);
        log.debug("Objects #0: {}", objs2);
    }

    @Test
    public void testDecodeBufferPro2() {
        log.debug("\ntestDecodeBufferPro2");
        RTMPProtocolDecoder dec = new RTMPProtocolDecoder();
        RTMPConnection conn = new RTMPMinaConnection();
        conn.getState().setState(RTMP.STATE_CONNECTED);
        conn.setHandler(this);
        // pro packet with buffer underun
        IoBuffer p1 = IoBuffer.wrap(IOUtils.hexStringToByteArray("0400000000008214010000000200086f6e537461747573000000000000000000050300056c6576656c0200067374617475730004636f64650200174e657453747265616d2e5075626c6973682e5374617274000b6465736372697074696f6e020000000764657461696c7302000a6d697865722d6f7574330008636c69656e746964003ff000000000000000c40009"));
        List<Object> objs = dec.decodeBuffer(conn, p1);
        log.debug("Objects #0: {}", objs);
    }

    //    @Test
    //    public void testDecodeBuffer0() {
    //        log.debug("\ntestDecodeBuffer0");
    //        RTMPProtocolDecoder dec = new RTMPProtocolDecoder();
    //        RTMPConnection conn = new RTMPMinaConnection();
    //        conn.getState().setState(RTMP.STATE_CONNECTED);
    //        conn.setHandler(this);
    //        IoBuffer p0 = IoBuffer.wrap(IOUtils.hexStringToByteArray("c79f74365db065581bb60c7ea6eb849812a4cea7e0757375c2ed5c6c316c4238aa6803d7dfe52284f00a336d1e01fb92e2e71e83149e104f64a51878b2192606f0efd8a0bf94bd379f62215fdb300fbaea9d2bfce21ebc169f65d6833872af32767f85629be8e8fafcf41e0722905559477ff638fe6d26da6a9c25a18253378b70b9504e9ae25c678bd8b44f4bcb6afc7c056dea914b9b760a08b7995bd376549f917af074e060fe24dd66bd3e9e3b39c3ac255cf1813c0f08c735077152b5eaee97f0ad22ba544ddd2beb36079afb1048860a3123705372446ff456e4a2ab75f05849ad91a519443c72f3c8c5b60266cf16110d3b69b41c8f7f6584c3f5a049756dfd0b0024dc494b049a35883fbb305e00cb8bb79d09462cc70266bddb31e798083ff2ee6a4731fd903a55033b12a482144d2be9797dd14d67b691ec543cda0ad8a10cf03bcee9e67e999ee109726f558fb8e29d56030adaf38d34c5f406ca3c0a050e40ec2ed5ca8d6728b6c78af9f9cc1dea46b98b2edba431116cca00b127d47bb22793356af9eedd2cb2580cb0d6e7bfb8d86297703be9a679bb260e5db5074cf1930175bf605acd2dee7b08957ca0967a6646519d3beae59ae9004df22a932d38fce93f38532e1406239d5bdbd19a63b0041e66da74b90ec231ed7c306bef2eb198acdc34012507a54c57fc61b9da417f4493f432762230e0da13de8d182adba1ad2d8960395ff9e93351db5f4998843c1045c6e83c35f19e406d056f838c48345c08635a537bd09364121953cea315bcbff2183b30404a16e29bce2cbc0711e2d47c87036e4fd89ada65edd7baded0135ff9f2ad6202c015f2e4ca6d818c4dc22072362bc78f0807968c0d8b91651158e5585d325ce1906ac330cc7871a155dec33e35cbd244da2ace33922eec32885656506d56be20e90b5737102051d77d5228b4f39fe041d00cbd7522c2b0680e29c64fabae611ed4ae28d1cecfe65ac68b2d7ac0907879e8d7558336441a251e055d33754abd2f21f4b34efc94ad97a38d4773398aa827488318537bd8d823d34fce6f02a203753dcd96fa67ecfd4af2a56f9b7270d19e04aa270298985c2c4035454d98f758dd8cd7372dc973481943e3b128047c323c09a72f91605efa9546d8eb649f035985632b3d76058113189886755c283d7629cd5c3f5dc4312e1a795b4f834764926fc22dc18012d7c2d30e1e2f60be9d42be4baf22a1839f815a701432448cbc3590902350006517c4692edd50e4f375498684f269cf85034e2d15ea39eb29d92694e80f773a41e48037ae7eb472d98f46fc981a9fc362ec8718603ec65ab656648bfa77b0eb88e8c7a14204614b605d2e35fb921523b3332e6b4e3353ef2ce843382962bab274ca6bf215f7b639faa9e84e815c2ea2afa95cce5dfaadd3a5b760c73a43659a5312cdfdb6a0f5314e86d6c3212a5c20357cfe5a42f6708f0d55b087c6b0324e385efcef96987b89d39d4773e44e632380208f6c8e9e74a04b2a98dd4981126e42c9e9af1ab4c3f838942dee867d5765f880bd450d665e0576d1f0fb9272d5f0184070f0732a8180e2467baab43ac5873fe141b4986463debaacebb15e1a3c73173c29e192de3c9cfd6511f49c771c37b8fa728812ed82b9fb88058569646273a81b1c302984e4dad17a07726a07f8485170c81f6946da7c7b6ed8d840d5461dd7f1655320f277ed083419ef937c3786db817aa7099be06d900de4a666e0b7f0fd40545e4746bc9e8b0496ef29832cd82b7da3b1c4cbcadfccf10a7d567b468dc25b20befcd7bf59ee43b94bf867bbbee1272bbc2c75470d1d45afddd81ace04117da0a230e1c4c4aabdffe5cc17ff3086c73b52a1a68ad47219a270a98dc9cba430ca2bca09197cf23314c24872e65c8552836fe9472d087d015161fd25b2401564a63d476d36776b170d39b1c2f65f77358228933111d0158a680fd9073e06813b3880121dd8938c0112cd491422a72bf0eae1f0717cb1b10d52ac2d034efd22ab305fa090136647cf5b6c7c55d16d9b29a7d48b701a76586305cd95bd402e96944c4094eb2963fc8b586f873057979df590262a725d6881c167bce59c944bbe9868dfb8aebea1850e2c3e7bada7a8f5d5339f1368bbb92ca9196f4f4026330f2e030000010001321400000000020007636f6e6e656374003ff00000000000000300036170700200086f666c6144656d6f0008666c61736856657202000e4c4e582032312c302c302c313832000673776655726c020029687474703a2f2f6c6f63616c686f73743a353038302f64656d6f732f6f666c615f64656d6f2e7377660005746355726c02001972746dc3703a2f2f6c6f63616c686f73742f6f666c6144656d6f0004667061640100000c6361706162696c697469657300406de00000000000000b617564696f436f646563730040abee0000000000000b766964656f436f6465637300406f800000000000000d766964656f46756e6374696f6e003ff000000000000000077061676555c3726c02002a687474703a2f2f6c6f63616c686f73743a353038302f64656d6f732f6f666c615f64656d6f2e68746d6c000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"));
    //        List<Object> objs = dec.decodeBuffer(conn, p0);
    //        log.debug("Objects #0: {}", objs);
    //    }

    //    @Test
    //    public void testDecodeBufferExTS() {
    //        log.debug("\testDecodeBufferExTS");
    //        RTMPProtocolDecoder dec = new RTMPProtocolDecoder();
    //        RTMPConnection conn = new RTMPMinaConnection();
    //        conn.getState().setState(RTMP.STATE_CONNECTED);
    //        conn.setHandler(this);
    //        IoBuffer p00 = IoBuffer
    //                .wrap(IOUtils
    //                        .hexStringToByteArray("83a11c7aced9c2762fd1daaeb60659adc1d50536db14df5b67047d7c8ce5f6c688cd672ecfedb6455bb046fb5d2fe318193d6e7875e8a4479e53f654f5b93ca3c3df26e0ef6287be154dbffe64f5c53e2fdf7a5dce37e55c6d4ee7eb7f7c37874cdd926ef55e7f83a51f1db39823778aeffcf826ecfab56a2b173fe6d4f3a066497bdcc9ef6573d7b5bf0f044d9d8d58d01acaa74740a251fc03fb6e866fd277c628f447ee736b7bf5f3f9e8afde80a78afb0327c99fbf6bfcc52a13b59c539c6b18bbb22b0c9efaa768295be4a06877bef7e08f31afece0f68ea9e7ab28f22defe81c5423817e48aa34230ed55b241ed38e6befa4b783b57d4d62bcd96d5407154f7945954cf1c6e5007347ad2fec50d0e958f171d7544be8d8346fcfb2d1eb63c6b980a81d462f3d26cdcb7288dc9e0683f7fffbacfd47fb7237dff0451d29ce28ffe88d761c7c8e3515688bce32a2efb57037e03b47797dc3b138a2d536a82fe5c9ddad4a3d1de8307faae658ad488f8016fb6e2bdb3ff559b47b6e0ef5b52225fa811e4699bc7bacd8d35fbdf2b037b37dbce49c11a08dca5d2834306eea7477c69ed92dd6fca6dad6e5bfd03b783d83cb32f0025d87718e8efb0ba5933be9e51bec673fb356aabc7df05cf81c9fdfde73477823f13fc7aca8f88faa6034204f2a3477133607f64feefad536f59ff94e5d1ea89f7bc49bfddbe98de6dbc9228dbbb0bb2abc9b737dbc0ce276e78783a918ec97ca7ca7a06c0e73df63229df7e1e8c666875e518bd914e0f2fbfcec99f974441dfa6c0ca0f33f3ed88c3acfdacb1ac8ea8ed4d6bf9a0d081be0f806fdb3f9a0519807eb623fbfb3adb78abce8b1d4c96cb249fdb79b732e76a89e1d767208be060414f453783d517d544614ec6e7bf14ef9ab7a22a8559f8f83ffac53fe7f954fb37f8af6a7cf73782349b0453efca9c6bde35014b36cf01492fd9f5fcd51601ad2ef1e768bd515476dcddf5687606e4d052def255190337bc635fb1a1e0ef35baa876a93ffbf6bf7f6fa5111ef0072e455ff88b67bd714ccd1d628fa96847680ee78f3b8303f9074dd512ff22d6282fbf8d37966ee28ff7f2bddec54a307958c61081a034d5b7f937ac1739f7c3ab077c68d7a33dcf7ff28f3bcd4d2794fae6b9cbf957ff84699fd6e772eb547d88955901a1fe7bf0ebbfc1df754ce6a7503b5154a8f35be55d9c5019c76b2c6b6aa7444b7fccf70b95c5171b52a3fe068409eadbbe9fbbff3623cecef7ead179bfcfa9efe7d4005c2a851b67bd57f88f3aa64b27d5e56ff15a94c3a36ffff7357d51444c6f7aa949140f3d075cf67577457ea9e6e411744754a32d83a5f6eccf496e72eb9f0794bafe5db6818f5ccb33547246dbee58afb3543dde2bf67b9371478752abcc52235111b54bdb2f67c1a1fe8467707bdbf9f55dfe679473d146286f07937beb2e57c148ae29bf9446a97ff6f9f1dccf2a9739edf8e8448e89d672cb2ea911bc62e0f2a9ee4bd96ff7688c06033ff1d6628c98ab40f28d1d66f47aa628acff7c3a96eb9f0adeb6a66ca3a83dff2daa95d644693545f7b7d2c2f963e0755714f688de6ad1e2b6bf9bc1d5b5ab9cbcaf8e9b3e3dfddfcffda6a2afedad0191d8f256e8f32e69fff6725538084d6f5436cfd5e7b96a81df59c7c529523ab9fd03b25c6f676cfffb55e4b393d9b83b51b71cf2a3cd67762ca4763a51ee7c79df5fb7ffc1ddb54d3ef8a99ff7846bb3b2c1dffde53b76db07b077f060bf26ff2586e52dfe7fdcf656874dcad0eadca3df4f2c3c8aa29d9e3f0bbf6b0758a1bb98c976ff3ca7d2563d608e48fb6dd965df6da3b97b5992d6bbe039e9555f7e6f780d03e44c6e56c0cf9bf351560eee2bbd53cbd935473f5b7bf601cf499becb68efcc65fadeb554db5b9940e4aa4fbddd57fbbdc63c3d93ca322b53db72aac6a35045967fe19bd7d4ab67d79dbede5d54a20f3ed7b7dc8b0f55ceef9ffff83a9a0753cc54dfafe4d93154b144bbbeb1476287bea8e4f5647b547b67eecc03bcb77681bdffafc6bbd87a0dbe830cfc3a054d85d544f2aa068445101469c32699fe497ea00e888b6caa3f9c67d3797d3fe1114d0cdf035a823df08fe50a7c2328f798ec500c1822858453f17ef5b477b62b557b7f73fedec968ee7a01cbb7bcb315a987df6cd9777fdbc9bcec03806f2cfde41d7e0ed4d9e69ef7b9367fd7fffb514c6bcc403977c6045b659c955b6f7e53e8073d045a23fe8f2fa34ac79d11e55981d49628748f9b914fadb3ca16edfef72cd9ac88a3aec97cf7c1ab96e6c8d6019a220ff8aad633047b714f2c9e73cb159993f7c3a03b3f54df889de5f0f5bf411a5bf95cf3fe2aaa445d83c03114c6446bd1e67273ea7df57f1dbde54656a747bfd6681d9cc983c6ab2c11727aa95773c014eca14c537ca36d117de1de597264edb27b3f65967bb2ed7bd37ca3d51eaddfc8ba857ef67be3af8897930457be5a331529cb72fff414f8a5541d362329ed4ea4cc47e4effcd01aade799faa99df2a8a94ef1bbec955f4329211bb3deb9bfbdb7f328ec0ecaa776a853c63df5329f8cc61af7656077e9c6df08f52aea477eaae7432896e97d553b7e3ac6297f25537760e84503d9abd9032ffd993478cc1ee5537b8dcb14f2d8a7b5b68dbe0e8ee35dc98dd113fe51ec95a654ddb25adf432829fa2381bfc92d9eaafb8a7fb6c1e66cb54715cb2e32e76cc51fd1d2b6f2cc9fef94c2ab8068461d8e8f40e6fa7ac6a7f00e28536cbf96fec6e4e81dc83ae5dd54a4f3f41e819fe7bf22d67a2e237edcc1eada2301cf0043ddbbf8aa281ddf29aaab3dc1e588673caf7ccc3af7be5cbeb479f513f1437ac5a061472c97924efed38df27bdde668eae631936d5167142ba06bc3b0337df7b8d503ada230efd66313a084c7727ece81dabcc0ce05328cf77d3e3b654e2e238f62c6811f60f641d7ef832816b7773fcaa6cf6f380c0bddc6e31768f3fbebfc7415e7e28df97fd4b2cfd7b2658a6f95681cb1475bc73dc3444982365e08d324977f601c9569740eed5219bfd96b7dc9b676aa57f9e0339d56a65b478df65b2e8650fec50a288feaa3393156c6e41e5b36819ffdb1e5b2ab8f82054677fcfcf08d2fd5c60ea2ca6497d44653aa47a7223cd7bf9fdcbe6bd475e640f29d6704750a707423064ffe1df1a6c74a7f68efca6fc0ea96ab5f6bfbb0dbfffaa65926ef047fe5f8e80c8eb727aaa5162ae4ff47419c50ebd445b140eefdbbeddcf624edef475f1e1a7e2e0360c23e034cf10a06018384f834bfac05fe8040ba2667184ccccb0443c6d065ffbef29e768fe5e7281dffbabf208bb064f859add11a7fd6edfd9e57d8af7a3d8a40d8ef04791436ac327afcd5e2a8afea73e0c0c235144900ae7fcab7446e5e866fc0c1020078307f60d34138c0606104b060fe55830bf80d0023a8f201cc1d552afbe9208ded9bc4cd34bba40b8beabfaa6367eecdd051ab51f6ed02b0c60bb67def37ea1897a075b6242e1d5f2ff9f11f1995443af6a37f97dfb8a7ca7bd8ca9fe29c02d397cac0ad00b8c5623fc183fda0c2fb8340f885e651834b0734a68f3f1897f0a0aa489a7a6327e040f81d1195029da640e52bba964a6df0940ee281168f3aa32f6dda3adacff3adccf7402629b6bdad5503ace7b97f9547b971c656f98d5729e99540c1030307f40c301ba08210304f40c1c1aa0616083389941452b57e3e2f2fb9b077efe7b9b9c616e61a73060823cad9b3fb9c954f932d93331a86df13a0680e6f07597f73273ca7d1b5023cf79aeffb80d0423c7e6ceabf5990475ff39364b27996b700f67cd388f818206060ff0bc1858674b7c0d506101cc618585068019fffcf7e363c9ff4490bc1098c62e8154db1ef7ff651f46f7ea2ee08c084aae0ea46b6e26e1a7beccb3be53cf794f2b566eb7bebbe2fdcd52a7bb5eead7b677628924575408d477df8f24117d1b993b7c75d87c0c0c2835606c45c0c0c22b02a2c922fb80759a3fffbbd991a2df4ab6f73af5ffcc03ff9c51ff44dc6c980c33f167b30f3df6f59f2adbbf9de8f6f77dfcffc4792cbd9ebb147a834106f37f37445f7c4798aeb5dc8a87e3a666fc778a07755cd746ab0607f00994034011562508e258355fd30d8eb07515abe6fd803e05c3d66bdbf148f14f41817ba5d36de491b9dc53574079f073ddd2fbfe089e5207af9446f75a1d42f999ccae8c631edc97399e51bd8a5ac9fcd52dd6c7930796f0336456d03080824830bfc01513418188128183fc80c2ff0340f3fe5dd2e55768ed4d496557fe2355e6f4d36ced2f4d30ae777757d5ed62d73e22f846d9fad4fd5023c563b514796ede4bb14f2dea900887aa629823e6aae1728c5593d07792f3930763acec6deaa22780a8f81c6a58656f8304f205418602068015dbdfb2d9a2217a21e73c58396cebe974eaa63825e6671a9ce66f6f6edacee43cf8180a5b07532819f6fbf80a5be63dd55c5767bec53af9a3bdb5559fe4d4a5ff9b4779b7d977ffe29dce39f6830308ac18385f030b0c0d002d2c060613c056034cecfab2e07a17eb596edce60eb8d2d718540c610feabc3dd5753f18eabffbabb4cd6ce80"));
    //        List<Object> objs = dec.decodeBuffer(conn, p00);
    //        assertNotNull("Objects should not be null", objs);
    //        assertFalse("Objects should not be empty", objs.isEmpty());
    //        log.debug("\testDecodeBufferExTS finished\n");
    //    }

    @Test
    public void testDecodeBuffer() {
        log.debug("\ntestDecodeBuffer");
        RTMPProtocolDecoder dec = new RTMPProtocolDecoder();
        List<Object> objs;
        RTMPConnection conn = new RTMPMinaConnection();
        conn.getState().setState(RTMP.STATE_CONNECTED);
        conn.setHandler(this);
        IoBuffer p00 = IoBuffer.wrap(IOUtils.hexStringToByteArray(
                "8639ae8685ad4e802fb905a7918b480416b013e0632e41773e6ba30a1ee089ddb94df6eff6b59aa6251a2707215a2907dc6b51a749ff6680b37792b6c302d43e80f4780361ab7b3c79de5f917aece673e6192e0d45606a5a56dc23ee8113b3381a5d428074f461db71f8caaefa650517809b63edc8412c1f88b4e4d43584ca491a89dfdbb78df1b00c1cedc8e2139fe831becd70527adf4d17760c1cbfff47a1116aaa8f603d3f5319a0688bbc215c1cae1cfb06b6546abd4b76cc7f32cbc84b4531ba2f539d6ae5c4c081bcc51a73b7c14881f8b6bddb480d8a4430b98577f15d31215480d6ebb9cb56931ad3703c2bf024c943b3c45c18717d467387141cdcc88f389548bc335b10ead0daf8e8c69e67f43099ab1f5f2afcb343c08d4b065ec7ce3a437d9891ec8388155d5bdae8dcfd6b4419df2d9c7ca584511e240cc6b1f04ccc098a74d5037c921e4f5916affa17ff71daed20d621687b12bd3f7fcb8f538360b39eb237ca05ada13dc433dc10c2504c55e5ca2e6528b3279eb49e4629218acfc33fce315c58533076d7e3fff6e49650d4283c8fa4ee766f93fc3d10b10bd10b8c2393e2a1da4e6c53dcc5ddbd6efd7b844b7546b0472346b9229cdb6e8d45f70f1e6d23b96cbb2c41fcd486e25fef021e19568c4617248e58ca195fb7aad5ca34dcf27ac7f03dc71a8b4831d1bbb273f6bba56ed9cdf49eef6c45df5071d19d9e8e23fb33b34a65648141cd61db72f79fa7944e3232cd8e30ba310d566fdac6d51b683a3c27af315ca5dc0f614d62c6672e97c036d181e00d6cf08b41a130d7a24783ad616593dc10753959529657f94aec63fa073ae24afe44b2d7075164ebc25305db954607b92c1c7ded5f88e587227ce411010292b6e392aeaeca456d64dadec73cac5de51ec2d3b530db0cdb9869fbdabe1f0aae10bcc1479dc927178a323ac0b2c1def11a086605ee0a66d5a9f1652b5b5860cdbd3594c8e2511c004d8704ccb2732197f37e687753ce0ed00717f20ca6e7076fd4d06b49ba8c665a2adc41e702753225868ace398baebb6944c29c149b838fb71b1e8c20ed3c9561129867c56bc800be10f8dba659f37bbe2242b0cbdcf342396e5ee61f327e7759500d4647e313937c81809b602af08493812ca199698ed35de9ebeded83e1ef5d8f8ad56c368acd7a6d7a05118541bf9d60bc3e45d64431a7700770c814f48f5dcd1c35270a5288b8cbde9333b5b8c40dfd6f0d31d51bea52e0bc6e6e4f46b1bfe85268a494a83d20668829dcfa492325e5f372f45a74bc19c9be07eda5bb1060376b0563081f541801b7d7ce5f7408e5bb11f63d0638419f7cb8aaaa55afa32dfb1e4f0df11fc355ad6c30405b8824f8fff87feeb3b5390cde76040008bb422200a571cd0c19fda9df620ad6ca881c833728081e7cefecc78b280cc06b4c7de3d1c9cebc04d84e1c43fb9fc8b52cc07e0eb15012872c0739322b1da9d7888b6c0f968863ac571837fd63457f98d574665e3cbe1f3b497fb03d1ab8e481985732de26051919d0aba7f18281d8f512b05a625746e4dd50e0c4be16ab4b59aa3cf24e1648ee9d74e4f3b2a92fc7828a5eb2040a706d52e354fb079df3062d404c46fb78de4931caac381020c5bf6b38fecdc5f7d66c3ea3fb087f4ed8ac98a81a24a42053282c7524c2953a5885c1ff5d736d46c472d318312f2a427dc3526fd513c88dbb8583d607031c0a2825f9e74428b859d8874e0cb013b458b27d549a41e4330682dac90e073b79c458dcb2cba317f816bd2dabdcee96d77ab6466021a23a932d134ba33279956aae938787a3a59216b53d50dc0554fe34b5f51d1e050f84e03a7442b29604684291a2ee79198a3911f8a54a1e47c0bf9ec25114f60dae43d4aa4639e5a5c89010ba3884014c2721cab878795f22ba8136f7d4685c9a5c348bda08b60a1ff1afe6d5578d52f5051eeafa9e3b9501701a272a880aaeb30fbc2db66a5e48d7c811a56c9a809c92567d8a10472c142f3dc38c0123e20ed3feb067a550e0a997b38061e191a3bb5b47a04ef70fdd94e69bfc9be160d8a8cc7dc163e8d595cc987c1d676a7b543f56305be60921c19113be5ea988c864b636e216c1c6d71319e0c96b58eb619ac63016ffb97761b79a3eea0016cfacadc7c10300000100014d1400000000020007636f6e6e656374003ff0000000000000030003617070020003766f640008666c61736856657202000e4c4e582032302c302c302c323836000673776655726c020036687474703a2f2f6c6f63616c686f73743a353038302f766f642f6d696e69706c617965722e7377662f5b5b44594e414d49435d5d2f320005746355c3726c02001972746d703a2f2f6c6f63616c686f73743a313933352f766f640004667061640100000c6361706162696c697469657300406de00000000000000b617564696f436f646563730040abee0000000000000b766964656f436f6465637300406f800000000000000d766964656f46756e6374696f6e003ff00000000000c30000077061676555726c020024687474703a2f2f6c6f63616c686f73743a353038302f766f642f696e6465782e68746d6c000e6f626a656374456e636f64696e67004008000000000000000009"));
        p00.position(1536);
        objs = dec.decodeBuffer(conn, p00);
        log.debug("Objects #00: {}", objs);
        assertNotNull("Objects should not be null", objs);
        assertFalse("Objects should not be empty", objs.isEmpty());
        assertEquals("Method should be 'connect'", "connect", ((Invoke) ((Packet) objs.get(0)).getMessage()).getCall().getServiceMethodName());

        IoBuffer p01 = IoBuffer.wrap(IOUtils.hexStringToByteArray(
                "030000000001431400000000020007636f6e6e656374003ff0000000000000030003617070020003766f640008666c61736856657202000e4c4e582032302c302c302c323836000673776655726c020036687474703a2f2f6c6f63616c686f73743a353038302f766f642f6d696e69706c617965722e7377662f5b5b44594e414d49435d5d2f320005746355c3726c02001972746d703a2f2f6c6f63616c686f73743a313933352f766f640004667061640100000c6361706162696c697469657300406de00000000000000b617564696f436f646563730040abee0000000000000b766964656f436f6465637300406f800000000000000d766964656f46756e6374696f6e003ff00000000000c30000077061676555726c02001a687474703a2f2f6c6f63616c686f73743a353038302f766f642f000e6f626a656374456e636f64696e6700400800000000000000000902fffe410000040500000000009896800300003100001a11000000000002000c63726561746553747265616d00400000000000000005"));
        objs = dec.decodeBuffer(conn, p01);
        log.debug("Objects #01: {}", objs);
    }

    @Test
    public void testDecodeBufferCreateDelete() {
        log.debug("\ntestDecodeBufferCreateDelete");
        RTMPProtocolDecoder dec = new RTMPProtocolDecoder();
        List<Object> objs;
        RTMPConnection conn = new RTMPMinaConnection();
        conn.getState().setState(RTMP.STATE_CONNECTED);
        conn.setHandler(this);
        for (int i = 0; i < 13; ++i) {
            conn.getState().setLastReadHeader(i, new Header()); //TODO hardcoded, so test will not fail
        }
        int idx = 0;
        for (IoBuffer p : new IoBuffer[] {
                // packet #0 // connect // 320
                IoBuffer.wrap(IOUtils.hexStringToByteArray("030000000001321400000000020007636f6e6e656374003ff00000000000000300036170700200086f666c614" + "4656d6f0008666c61736856657202000e4c4e582032302c302c302c333036000673776655726c020029687474703a2f2f6c6f63616c686f73743a35303" + "8302f64656d6f732f6f666c615f64656d6f2e7377660005746355726c02001972746dc3703a2f2f6c6f63616c686f73742f6f666c6144656d6f0004667"
                        + "061640100000c6361706162696c697469657300406de00000000000000b617564696f436f646563730040abee0000000000000b766964656f436f64656" + "37300406f800000000000000d766964656f46756e6374696f6e003ff000000000000000077061676555c3726c02002a687474703a2f2f6c6f63616c686" + "f73743a353038302f64656d6f732f6f666c615f64656d6f2e68746d6c000009"))
                // packet #1 // 16
                , IoBuffer.wrap(IOUtils.hexStringToByteArray("02db5565000004050000000000989680"))
                // packet #2 // 59
                , IoBuffer.wrap(IOUtils.hexStringToByteArray("0300017c00002f140000000002002264656d6f536572766963652e6765744c6973744f66417661696c61626" + "c65464c567300400000000000000005"))
                // packet #3  // 14
                , IoBuffer.wrap(IOUtils.hexStringToByteArray("42000000000006040007ce4c5f73"))
                // packet #4 // 7
                , IoBuffer.wrap(IOUtils.hexStringToByteArray("c20007ce4c6743"))
                // packet #5 // 7
                , IoBuffer.wrap(IOUtils.hexStringToByteArray("c20007ce4c6f13"))
                // packet #6 // 33
                , IoBuffer.wrap(IOUtils.hexStringToByteArray("43001e610000191402000c63726561746553747265616d00400800000000000005"))
                // packet #7 // 18
                , IoBuffer.wrap(IOUtils.hexStringToByteArray("4200000000000a0400030000000000001388"))
                // packet #8 // 52
                , IoBuffer.wrap(IOUtils.hexStringToByteArray("08001fdd00001d1401000000020004706c61790000000000000000000502000973706565782e666c76c200030000000100001388"))
                // packet #9 // huge connect from OpenMeetings
                ,
                IoBuffer.wrap(IOUtils.hexStringToByteArray("030000000001b71400000000020007636f6e6e656374003ff000000000000003000361707002000e6f70656" + "e6d656574696e67732f350008666c61736856657202000e4c4e582032302c302c302c323836000673776655726c020082687474703a2f2f6c6f63616c6" + "86f73743a353038302f6f70656e6d656574696e67732f7075626c69632f6d61696e6465c36275672e73776631312e7377663f7769636b65747369643d3"
                        + "563333562613330396634393030346139303366323264623663323564393330266c616e67756167653d31267769636b6574726f6f6d69643d350005746" + "355726c02002472746d703a2f2f6c6f63616c686f73743a313933352f6f70656e6d656574696e67732f35c30004667061640100000c6361706162696c6" + "97469657300406de00000000000000b617564696f436f646563730040abee0000000000000b766964656f436f6465637300406f800000000000000d766"
                        + "964656f46756e6374696f6e003ff000000000000000077061676555726c02002a687474703a2f2f6c6f63616c686f73743ac3353038302f6f70656e6d6" + "56574696e67732f23726f6f6d2f35000e6f626a656374456e636f64696e670040080000000000000000090100")),
                IoBuffer.wrap(IOUtils.hexStringToByteArray("4300120c0000191402000c63726561746553747265616d00400800000000000005")), IoBuffer.wrap(IOUtils.hexStringToByteArray("4200000000000a0400030000000000001388830014d302000c63726561746553747265616d0040100000000" + "0000005430000000000221402000c64656c65746553747265616d00000000000000000005003ff0000000000000")),
                IoBuffer.wrap(IOUtils.hexStringToByteArray("04007dc400010108010000006a42a5b3b597d08decc518618c31c688880821841022226eaaaaaaaaaafeff" + "ffffffffffffffffffe17384c5790bb1ae48f4812ff082e31ce7381ccecffdfdff7f16a61525c7586c145624279c6d15b8ca145c5b11a396dc1ea405aa" + "eb584a82022a4aab5c0d3ccf732381d8568f05399f98b47eb22b1a714aa116482deab090420000000000040100000101c4e3d6aed29dc420b24cd22897"
                        + "948f0d68c12e16b640bc736918d278b5956c2d44e358010e8ff699b91bd73716ecd70b891b3791263b9d380554dccec61646ad51dd5e9ed429a3a4a2b0" + "51066394111179fbe53f6562f3f461cd49fb1b6b662e79535391f32d29668e3494a211ff442e2de649475ba8e480f6de4ef5b73dff6d3356")),
                IoBuffer.wrap(IOUtils.hexStringToByteArray("8400002e6a5f2bd5e6b81389f5bcd79c93cf8dc82fcde9abd1af033d756343a53488344bd53c15f9202ac59" + "299268794caa179534a2132b68a1da926f5da1ad3566d43223d99437a65ba4f829395c95c94f11838650cb6169785929758aded8b6da3ac86ba422805e" + "cf6ebfc0ecfa8d37a2fde5f7feaa919b154c9136251a8a4aa09753616608175d6aa9b6995a1b89a8472118833d8a6eab81572fdde05ed5f21364cd97a6"
                        + "a7abc24c6fcef545e2d2553b3152384afd567957b749125404821853a388400a2597955cb538137a5b79eab101599c9e71ad7c5d6db1039a1274771d2c" + "eb2cd95eb8ac9befed41d2a79c34b630afc146979b549eaf9d50d952895f63b56ba504600008e0005010932000084074202becac8c293f8c2c3b658622" + "5827a0342932209024ad6308162a489b0c0336fe9de14fe139c3630dcd66b622a6e0892b6c9673ce3a23ce9f3e7db683bcd42b304e2bc951c296bad8b8"
                        + "2f8d0e8abc3d8d271005414b939d278939dd98396c2906fffc41e6cede4d1138362cc1708f4247c30771f80acc29423a3214f3e478350dd11a6353fd95" + "ae16f4157ed26c0f412c29e347a7e9f6ba6a6a994b262cd7535d3cf13e7f4f4cea6ce4e276c1878257c4ae1567630569ee959f17be28cf26064404905e" + "a16a9db4a4c1633da1cb4d1fa03443cf1d3a9c1b8810a784e74ed3d189363379ec459a1cd27059851e8065a48359a23fd911974c8902087c674e893e90"
                        + "b24977641c286330b314b360d50b3a7c559d70af3a18359d17b413b79d17c7857f80ad25141621a9d3ac946706625e367789865cd02dd9abda5ad36c0b" + "02bed04e90e56d4d5c456f72f43f49c870f05f8094f17f4e8859e40889d7c056030ffc9de4024ca472461a14af4621d3408e702b6b3307214f6215d102" + "b35b38784f982b063a06bb5334c201c8ac5e0ddbf89fc6868d831e02f59a8b23de824852e4b9185d74d0838c9cdde42ce360c740e191a853d9180373fe"
                        + "a5905ca943bd662110c561b31c0c0e0ab380da7fc2a6c262d18a104def5a489af528a9e14f60380c3d9fe48a00adbc48a25db7122e4689071098101861" + "0a318649d6bbb4089c64214068e853d1da031095162e115e167286848c5229a0529675108471b5de14f2b71c3ac92fa0eee340c740b29ab460982b74f0" + "d81907fc3209224c42c3220712ad9594ed3a08b5bd1b96f5a17085be34229640bb4a5c046b69aeaec8124a3510b0e148e61e01c0b890a732a6ade87c78"
                        + "4fa30f1721063ffc5d8573a9f1b1c8984d84b296365952241988f045702b8d226c43582a6f943867bd5d869a7254fc8902e0a7f74f66a509f172ae9684" + "a0c83f9b85291b88915150ac29e1c62288cd0e34725a889f288488d0369ff91a0fec4fbc5ae74682e0a17cc4408c186874d82446f596b66b170118e233" + "614f1069ec2160d9625312cdda23a602790a22152f301c64fa45ccc60c27c04d1ba240543511d2b6df077dc85a88640dd80850fa2c0a18dcd6c0cacd4d"
                        + "88fcd3da04c15fc19b61a0238d443c98a04314c0dc06b2878dacd2c23cea36c02042c15c35480c940f4eb189c3cc4dc1a27ac254fd69a2db187853f899" + "3afca21a7321e09c15a59a95938de276b4840b21e831d02c994e81195f48c29edf4ca764190ff328aae09c21f6825318ce242b061608ff160636046414" + "bb02fb8ce836effd2b1c60ce6d5ef53b1c56d830c05c27c9d606414f0b0ac119e1787220d25b3195dbd68a38d778b1e1d6b5ab022854142db0685f9822"
                        + "6b68da2663538884a300a7a146b1c6162af268051846e8c2b06280832d6be1c8653476048c618582fde872329ee8d029f352ea4e44a1422292a6342ff2" + "b641840306960cffd32c3da0436394c9ad0d8300a796a6ab0b574c6160ddda03c49ff015490d9d0a7f3bbc01fcc304d46e31ffba0c27ea86e8191beac9" + "8dc16053ce26b418e7f150a744602650ea227ab7b15b6052d1760bc29e8da4637c4b0f60dd191e8343050186fe0699fae01dc480d2c27563014f27659e"
                        + "b5630154ad06e19286dff5fa22034c052f18d3214f593616c467b06c2d95a44fc11c088bc14f962903b9d6fb0a1819e1442bc220a7b1437780d061c085" + "b01488dde8dd4ea0b55fbd89076673ba16853fa38601907f7a20f4f45c1a3fe06b7f96a9623efbdd44f06360948c4")) }) {
            objs = dec.decodeBuffer(conn, p);
            log.debug("Objects #02: {}", objs);
            assertFalse("Objects should not be empty", objs.isEmpty());
            assertEquals("Buffer should be empty [idx = " + idx++ + "]", p.capacity(), p.remaining());
        }
    }

    @Test
    public void testDecodeBufferChunks() {
        log.debug("\n testDecodeBufferChunks");
        RTMPProtocolDecoder dec = new RTMPProtocolDecoder();
        List<Object> objs;
        RTMPConnection conn = new RTMPMinaConnection();
        conn.getState().setState(RTMP.STATE_CONNECTED);
        conn.setHandler(this);
        IoBuffer p00 = IoBuffer.wrap(IOUtils.hexStringToByteArray(
                "030000000001531400000000020007636f6e6e656374003ff0000000000000030003617070020000000e6f626a656374456e636f64696e6700000000000000000000046670616401000008666c61736856657202001057494e2031312c322c3230322c3233350005746355726c02001b72746d703a2f2f36372e3136372e3136382e3138323a313933352f00c30b617564696f436f646563730040abee000000000000077061676555726c05000b636c7573746572506173730200086368616e67656d65000f70726976617465496e7374616e6365010000087075626c6963497002000d35342e3230392e32342e323138000a7075626c6963506f727400409e3c0000000000000d766964656fc346756e6374696f6e003ff0000000000000000470617468020000000c6361706162696c697469657300402e000000000000000673776655726c05000b766964656f436f64656373000000000000000000000009"));
        objs = dec.decodeBuffer(conn, p00);
        log.debug("Objects #00: {}", objs);
        assertNotNull("Objects should not be null", objs);
        assertFalse("Objects should not be empty", objs.isEmpty());
        assertEquals("Method should be 'connect'", "connect", ((Invoke) ((Packet) objs.get(0)).getMessage()).getCall().getServiceMethodName());
    }

    /*
     * @Test public void decodeBigPacket() throws Exception { log.debug("\n decodeBigPacket"); RTMPProtocolDecoder dec = new RTMPProtocolDecoder(); RTMPConnection conn = new
     * RTMPMinaConnection(); conn.getState().setState(RTMP.STATE_CONNECTED); conn.setHandler(this); Channel six = conn.getChannel(6); log.trace("Channel six? {}", six); RTMPDecodeState
     * state = conn.getDecoderState(); IoBuffer in = IoBuffer.allocate(0); in.setAutoExpand(true); fillBufferFromStringData(in, "bigpacket.dat"); int loops = 0; int packetCount = 0; do
     * { log.debug("Start buffer - pos: {} limit: {} remaining: {}", in.position(), in.limit(), in.remaining()); Packet pkt = dec.decodePacket(conn, state, in); if (pkt != null) {
     * log.debug("Decoded: {}", pkt); packetCount++; } log.debug("End buffer - pos: {} limit: {} remaining: {}", in.position(), in.limit(), in.remaining()); } while (in.hasRemaining()
     * && loops++ < 25); log.info("Decoded packet count: {}", packetCount); }
     * @Test public void decodeBigPacketInPieces() throws Exception { log.debug("\n decodeBigPacketInPieces"); RTMPProtocolDecoder dec = new RTMPProtocolDecoder(); RTMPConnection conn
     * = new RTMPMinaConnection(); conn.getState().setState(RTMP.STATE_CONNECTED); conn.setHandler(this); Channel six = conn.getChannel(6); log.trace("Channel six? {}", six);
     * RTMPDecodeState state = conn.getDecoderState(); // tmp storage IoBuffer tmp = IoBuffer.allocate(0); tmp.setAutoExpand(true); fillBufferFromStringData(tmp, "bigpacket.dat");
     * tmp.mark(); // actual input IoBuffer b0 = IoBuffer.allocate(2); tmp.setAutoExpand(true); b0.put(tmp.get()); b0.flip(); Packet pkt = dec.decodePacket(conn, state, b0);
     * assertTrue(pkt == null); tmp.reset(); // add the 2 bytes IoBuffer b1 = IoBuffer.allocate(5); b1.put(tmp.get()); b1.put(tmp.get()); b1.put(tmp.get()); b1.put(tmp.get());
     * b1.put(tmp.get()); b1.flip(); pkt = dec.decodePacket(conn, state, b1); assertTrue(pkt == null); }
     */

    @Test
    public void decodeRTMPCamData() throws Exception {
        log.debug("\ndecodeRTMPCamData");
        RTMPProtocolDecoder dec = new RTMPProtocolDecoder();
        List<Object> objs;
        RTMPConnection conn = new RTMPMinaConnection();
        conn.getState().setState(RTMP.STATE_CONNECTED);
        conn.setHandler(this);
        // RTMPProtocolDecoder - Failed to decodeBuffer: pos 0, limit 4644, chunk size 1360, buffer
        IoBuffer p00 = IoBuffer.wrap(IOUtils.hexStringToByteArray(
                "1703030578d9f863f2cef8b8cd9d2f9edb11f37f4ecf6ae63eadc21ac2c2e81b83951537ebefad8b4b734ca81b51f0a057c6ea0a2807831178ef5a5ac0fb6a7ac37bdd9ab8116f614d925876f8f3ea6318f8305d51b8a2f1e258147428cdb8d56262169922b3532d701a6b4d4eae86553a54fe5bc590d9d8b0c2ecaa910186ab2d2a5b7508078e87705da88c7b7acc9fcba57b84e0d02f032e8f50d2f04db3e358d87175734af810e75db5f38ed86e39ab9843f3c21bb6526f0c6a37c6cfc51db57bf3bff10fc836851e27e54e8fa6fe8e58a7059e5fe102ff5798d8f6078a87d80674b98192674a194665a220c1fb39625d5128ba27fd5d632815c92d0be4eecbef2c358f31a028452a56233e9124e62b7eadeb126a4f29b13104cfbed3d5af691716928822f0e822b3530f5ccf9262f8241a5a1df94fa48366870b3e34010a0d4e192b69bb5c12f968f36db07654f36c405a202e751c108b1ea5c965e10d6f66501f25e7fa70f771cf4eab3eb42526cf77c8d8a9e657f9c565e41d19402dfe3fac5d8ba0b9ec59800c0250275e0dbd6ea744554c698a2c72102b549b14c8e649f01b6c750193b4d62c157b899e9be1ffd212694958bab73365beb7b4c14104f692a6f3c085cde4eed89fd6d9546372a29930085097088388f0a75bf089ac5eb3fb74fac0bbe783230a39f2c326394f2f9c28b4c683a40205cf8fa97ec8980f430e6e73f6b4b6cbdc632f8027c3a0c1d438b065f25842b7997c092fd39505d940d4605179f89952e28a2fce9e5cca32e28e24c49ff4273d04535cf791b6bb2bba3735e79ee941fff414248bec8c574eeecf21d313b8615345bc031b1c4fe47315c63debbf16c106141e34b874baa23d6da4e47e1df9740e710d59216fcb2d002660d4f3d4a2ecc26c2044cd1ff3ad240292d8696b09dc23c84051d56e8fd931e5bb3396f6f40c9e37cf16630cfc9e158c7fb1892de3812f3dceb9cd27d32d9c384a8d0a1cbe93136d6d0e521bf4a9a1c73ab2a2e7e88a13e14c4df185094095545dfb09213c5af298541c1c6ae787dd2114aa3c760485aa22c4de9de105808a4ad74b6b30c349de2721456c5ac62fa4dd7feffb609045c6d930cec2e4f9dd7117d8365feb3781c83bcc1ba5b835d77530c2a7e2e643c6cb4a81ddae92d6cfceda38efbbdf5bbe196e3a8e41989c8ded0dc577034ffadc88f6bddd922ed185c454544007e73856dfd5edf140dfca105cec29d7b9100a1664f428264d8cacf6f365156be76a58c4c4520180ae54e1b4dde9dfa02775aa2caaa789cdbbc0077872361de9e046694533d4dd6ad7ec9a18dff5532d90117e12abe4876c2906febf4e2d07bcc4e04e4cd35f6ad9669c14f47fbe80d169fbd2aa9423574d3dd5a2812e8132c50a4e54672437868587e7c5d5785621b24b9ecb2280a6713655eb7e3aac5ff510271510b4d67e282157d3122e28819f43dd3f39fee369451acedc157164235af1c3b749d3d773b322c8dac7765246ee9973ae85ef6d862a99f780a89cf66faa6d03af74de83234ee1de624f3c6fe607a5605d015ba9838e11b8a4786ccf2586a530a775d3f047a7ffe6afcba4be1dfd26077fa5220fc317d2b2243a194fa89b545d91fda964cd6a86d04c0c0b40509bc919b1bb0bda282765aec2afb67b33d209cd54e1a866de6d2ed585c17113edfe86026094e6a045fe2667e296d4bb68d93f976449c8cf11c5242dbe7be2c9af1c7c71a102fd5496a81c5acbc28748cd9c87f0dd14a1934db77f06294d093f8b4db07ad248b9fe4d2c6832889bab08cdc7e9184207a1918a72a81930c2c9592d370ad94e52c4d4b2babe9078a9a124f493cdbce67fe403c0be4cf8cdee0f7f0863bccabda37935505247b0146617c8eca7a50e227815bcc0e4271f9d2bc77423db7b3464bf81b6eb729e4cc7351e747b3857dc6782ba9da7b809d07013a5bb3036214191cde474116bb8dceb170303056dd9f863f2cef8b8ce6cb78cb4d4cc92575d9cef7ce92d75f0f63a4cbc74822af2427fde24dd5c58407920a0af7e1fd4ea5e437d8e1310d5868fe70269d248176c750ab33e4a1c3cffce67059c30b6d5383d3b666a282c56da1ea7a6df1ed3d4e49b1f5fd4c1b18cf40f3cc470d9e1da61064449e8883d91b8ea0223f0fe065818818b53bbacde35b3866e27a4ceb2df2143a885257628e174726d6a3c790753a5b9cc07f6a23bdb86a208f3ccd296f3cc17aad4a55c0477276d02002ff863303fea3e095c011db2876a6133c1371677dab8e106df9c458b60914a83688835c06de210dde2c16c84a7eb3e8dbf44a84e98eec975e68d154f30562a3295f838b6c287a8e53f55de3c0168c68a5e6f88ae2e63c7b0cb4c54a6881a44edc09f9b75d414bb7bfa35b2aac940a7146865c7466de063c8bf9e1ad3f49435bc62c70c53a0f824328e1436385fb972df500ad0f9ff6a900234b4921b3701291782d6427f1513db70281f13df0ef95083c3fca91d0ae706e57d4bafc2f9527fde9d089fc10bab5880cc2853c7d89557a282c2abc88dc423a8a5d8d09e4e4274c1da77894782e75957aa06ba3869c1f0997a732969e1564f02a396e1547302049c008bc49f6b0571def0b8c5bb74c2c08b7a53eb8471e1097f2d29fc31842b96f2cea8aba9a63f1e24da07552340ce6d242675ab2f91a99041295bcfe23f938ecf1d7c3ebf9f4c9ca0ace8288abd2a22756faa7a42ce0d1e70a4a21537d3a52db8f72df5dd8fa47bb69e22df66efe1be4994654c75cc352266da5b8e4788b7a0b604f33a077c0d18be1b669a8123c696dbee53f2befd05df517fcf3523d1c3437c51089e49e14797da8527b797d17cebe17226741464c3b7b12893b32968a3f0c7f67e2969900b877b97ab14ab64fbbd9c20ad47bdcc82dadc56422933f37cb8fb07853bcdd5dc031e8041abad41ffc6745fbf670dd1bba909d6be1bf41b1b0773950fe79c3c4e66550a64214e534a07ae5c0176a98c119c449b6c29fb60660f19301fdac3673751d0ebad842b8d1454bd148188d57e22c7fe5762e97aa720de2ba2d32e8f5aacbf693c58e0d3544e5e2189419a352f6ce6c9740b4ddddf5044f2f680285286100cdd3424701b7ab952e5fabe1bae62ce0e9d8a199290c1cd9f6dbc1ec02441152de5a6bcc4a4ff8b6c16e0d98f7b302278cb0f2141eaed732ecd0cc5de0e5de137f7338b01a6e8c3e140547a597c809bc58834ac930ea220ccccce6df83bf25c45b490f4424fcc7705800b97417bb11bb0bf06e680e88ce0e58cc210a09b921b5882d389307c9ce0bfe56e286d367b78c7c3f02d9131bca76f3039cb3d8c43c3e7c8a5e859829d377718e995d7473d66ce0d572476b60dc921fa895dfe5e834d9a0afb36239e572582442ed770a0f0ce409cd77a777550856b3cc342924aee8a709bd2dc6685b5333b3362405e1744ad9c1c041173da63f49ab5cdf2154046aafc2b972750faebbba3c95c39a87bd5736fcdf3c67bc5aead9b84f21c46047253224bb5961325658448fc912800255d2ece8b8e323a479272c0889305d73a1f7e126cef5948e18f822519974835ca865fd9a5aa4350c238df7a1c317afa4a2a52d7b528767520f51fa6db36e21d9771e444c65d9137fe9294f544e4c6fe2c6759c663faac616b9ece8375f6c12d00f4624a31c050100a51561de49725be9fffac8f70937cc27550fcaad06ee1935714ed479be588891dc0f88ab395cd550ee2e4635e866b060ef5c1922e585f912b3df94c414e19cde1d62461e1cd98e474b5552594571e31a2b722bc7a6f8bd2b3a89e8f462cf2d6ddd05489333fe5917be0629e138180c7760497b8f18633e4b0c1bff99a4242f53b7ea7aa1f28c22aec72834088e93c6779ff9ea43bb2de2c8d34135c435ea3ceb99dc7faf7804efef04be5df5eb7a2018caf3ccc5b667f170303056dd9f863f2cef8b8cfa070d31e174fa8c12dacea9fc8247fd41f4664f89e1ffba5e365e27cb173d54d9109ee798d40e2f3acff4300d1a5e74ec0a5a368cc35f2244911392bc0842d9152c2320621faca6209318a11d7b4afb2d91c180705a70eb111feac0ddaf57cacc5973a257c5154c1a5e2097e98fcce73b7c71e74aa09cba1a8577b60f4a796e64debf39753a207ea21eed98ef2358cc3189014145ae3adf0278a2f0e4887599d84a681155e677aa6906d2ff225d50b70ae040739232d0c91d9b602110ad604ea8ea31859040e9744a9eb99bfd02a31ad120b9b3b15a4e7aec8816a3780d6980f9a9b2f6a86ffa6f188f3e1acd51fb61a045bcd060972cb42bd7b4b6a2576e82153834807d4d9af241cb6f7e0a268ac9d219ee5eea7be0251b8ede2a44681ad59f26d47d0ec29d0d2e73a754493d4edbbc0f986afdef3f56c8abb34971d0449ee579feffa2f4cb64a67f875670b617db0358e67e5ff93d887c17f4f4b286c95cb25c63dafb4719b2c6c21a5a68d76bff6e40c62fa4f895b16020b901add813f427448f407df4139d07c42489a73daadb859e7bcac0e4f3e87aa9cc0eee4ae8bc5181a4b71f739d412aa36d14ba5c5c939e4285cd132e8b39c5e3c363b65cba66929c4631fe3ebf6b30bba3ebfc75a742c5eb4f6b534e1ba5abc4444bcb8527f84a8f26aaf2fb23eea7e93dab52ee4664fdafed1ed8563842e19a337a11dc08e610b9d07c8b738ec0cae64352d5a63be25aa70596e45a59c81534fa78f7af0075257362800792f07fd629bef0ff1927c0ecb0060cd9b0887b9c984fbe54443091995778cb49d8ac801258b2fb88717b6e7775e885d3fc493251b8d6b72cfab76ab889e0e1402e62273e943b8d440fbfb90c11ded9553396a1123f981e61d040d29e4590a86bece98a34a74df597cb804af8c7df5b4ada503e74af75f783252f5c4109ea63f57a10c70c0764122831c9d48b57acdf22aabef7cc66279f8ae2da24d484e1b7bf00bb0e6672405f603ea6406a51a7a1511a9c5af26de386e111967ca2d3948ad91259c12dfe5e27cf9e4dbc2a713a6153f27c78c6768213ad13f06661b1e8209623f81fffd94b6dfa621fc13f45dcdc69fba5fba92859e7dbd6542a2c90fd754df24f553f5a46b2d464efc4ccec6457581c68415d7aa65157a87011ef87543d4ac02b0511c73742d4321274ab2aa056d0c129807f8ed28f2c71f23fe4d00b915db2401525358e2bd279cf97d30057d2b15203ca9393df1b28c2d99fe16ea38f77214cf07356668dc687f593157c77572510e6180182cf135a29c03dee1474489aa655e2e735466ef0bae1ccf0691ad3d9aa2033944353809f97ac72cfda3b24cd20b897da07ca8b073484d9a3e16d61654b0be8d5a2fd75ec27cbbb3cd88ee8d5f628d67ca490338850ffade9b61a1e8dadf07a0a9612c2085511b450db6efccabd2d1ad59810725cb8143296433f3891f3b7a58fd7e4d0811b5be7da3bd45986aeec10ec215f91d22c10fe983c266f03a5f0d260c8d286bf47d51549f9491b274fd57265b5734cd9f01cb8d9cf081e18a2931b32e8fb9ac5bd82e72cd285cb59949883baf87fa062e7dcda5e3756adbdf0e6261204d13194433bd12a9447bab021e5128ae0cdad0a6f26e578397ef1beb42e6a0349866553d03988427d5b3d060703b76759b67961748a5ff5ed37f773844373c7c739f21b12c224611b04a673ec401eef0bebdf78aadf97cfb8eb97cda2c260df87631b72c49fa9392d1669d401062d45a326c15e3d2bf4f6b72e56f0e9ac937014aca03b5c144481d8de8824ba2a2d8da99e93ac116300d83199ee9482db38be778edd18ccd4f205503a23132c97dfdabda124f75bacf456f86b3d1e146bceaed29b095cb0d2b6a3293f55b3a466225215ef05ea5491e73b2807ea6b75ed96377f778c594b57109a38cc67ed817030301bed9f863f2cef8b8d08439800bf2649cbeae6c33bac8b31cf2a02a40f1d651a3884d5ca1f366f4a0f4d9b48a8457c0f9070530496e0588c7f653ce83ffc6a55ba01937d1a487030e0ccf2b1d1570b0e5a3d3b56db2f9c25b698588f833a8697d48a0b457b5cb98e5e9a59284c1aacaf2f6dde685a8d84791342d8680ef3210cc3822a14f1d04b00ddb10291b992501541261cbb34e71532a3124fc92a21005fd692ad499f5b2c1556dfa9097f4c3afda48582cedd341adff827e8d2e346f05aaf8fd7880cedc3cf6105a0c367f15d9a72579b10a83211761d197aa8c15f26053e01a7b57afc92900b0b5d60d87f2eb9fbe972fa911d70873122723275531f76fbf5cbbaf07764f41a2b5a7b4fd9927cb736c4a8d7d31e594e7923bbd6ae373339fc8245abae7d63f78e0cd8aa2a39f08b7488245263d5c5cee554e18b91470226bbe9cbd7ac7c1e4263349c3ac782546a0190e68f5674e1e0ceeeb52d6743a43a2783ce9ae4a5e9b835df402cd080fec041e0a6a9bafa391d9fb9e4fb384b632b684172202ac76c1d70439c9758ab2605fb1b52601513e15eaaac576a3497cf0a2672f828f7d860178d79baafcac9637bf895086fc509f4f5e25378397bde2"));
        objs = dec.decodeBuffer(conn, p00);
        log.debug("Objects #00: {}", objs);
    }

    @Test
    public void testExtendedTimestamp() {
        //byte[] buf = IOUtils.hexStringToByteArray("c62bc8fb0ff2f4705368de8fc45af6bca8568b90ff593764ac332775fef77e8827b76edfc9d8e2ff9fe22cbb7c94c5fb0b4130970474bf74be4af768961f05193e6ebd7bc5ddf76d597bd672f788d1affdf94c5709d2e8bae6d80bd425a2e719f2b2747da1390d5230f7f8bebd17baa50ac98539bd7b11ea977c57a482f97261f9c622d499fb9bd3e2b8a24b9b957abeb57df6b94a12b36983d02f242740e8bb3f8cb2fb540d1d8767f4fb2ba4f7c13d7e5b7fa115fb03b4aab5e6f197c9ee228a6ebd14177aafeac75dfad6ae621ba0fe27d57f5d2ae4ecfb7f1ddab0b47a0130adbb27617af93df5826a63eef7e8b2a549736b5f175f7d49f9b7bf2f860b5ea50cc679ab9bbd4849397d49424debe4af2cbfbf55be6d72505fc9beb9affbacb5df5f97bc11f378c08276239d210407bf9b6b525f5eff37bf93dfc57635d56a27135eb588e5efd85258cd565dfb27aa975b1745f5f97af2eb9377e796ff5f9b5c977ee08a9847543230beba557fdf15ef7fb1fbfddddfa43bdfbeefa4ebd5a939b7fdc6efec8effcbea6eeabfcbcdd9edd427a5bf5b2597eaad97d7576baaf2e6e4af043a36515bec83f41bef74ff146f77ebbdff11ef7f4fd16ff423a45d3c4f2f5be6f5e325ca6ec0fe4a2fb752a9765d17994cc7eeb89f457c10719ee5fde780adfebf5cd7ea8827beff93df90bdeb8bdfbbbf6ef7fab3e5aff09dfbde2737c5d7afc65c9ebdc9cdbfe276be83f047d80fdf095fa5f979bf37aed572760725b932539abe5d0587b93d0fcf541ffeeb2f72683fdf7f9bbfcd7fe5af522fbbfd93c4137cb853c74dbae5f5e5aa42ba0f61fad66ae4bf57aacd46f156d19b157edec61ed1ea9ff7989bfeeff526fe989eeeffcdbfbfcdaeb88ddeeffbdf788e2882fdf7e7c637fcf5cddeacc6efe4932baad7a096c3fa7cb542391794b41ff2f4ee61c4dacd96af2e8dbe1ce6eebfeeb35d309f7efd17e23a2ef7413acc6d7f09eaabd7955ab2f3164b37bf57852b6ebd595faed551bd7cbdb9615f63af15045c9641c85707b1fc84f5722f92ffc21dfba0aff84bbdf928475e4fdebf8ad7d7c95cb7f8a92bc658edfc9a0fe5e717f7b79b527820e6f37f13d6431c754aad75ed8fd81ef607415de97f3d457ad6fe2fd57f8434eabd97f7bf924a7d59fe5efe79b11bb32fab496249eafabfcdee49f139bcd0e708d79dbce7cc0803d2f554abfc9ed6d1341a0fb5b5314bbeb293df96b97d3f37af84e87d817f7be491bedfcbbdf4ab9bd12937c6422498d520c8ff0ee9e88b8ffe6f7ea4d7cddd3f0968bd00fe2af777f649d79cb4fbbfcd5b0fe5d555727be8f597c9d1fa5d1bd1287f64a995512690979a3edc31cde4101eab2cb4c99460fb8cf7417569bd4cc575edfad14577b08fad7afa2bf6fcbbfa13deb934f27277aef7f5f92fd7277f97b7d237ba9be4e50875f89f6ec6de3b3435c9ec1ae6f4f59290ff7bbde5a7c64b4bdee806f46d5273e761cf635dfebbf752fd9bad671fee7673d9556f46f5d45fabd6b31bd7a2faaeeefaa7f2f7e8e5eb593d12fd586a3f1908404400001500018a08af01211a148daa9cc2419144cfb7bebdb53591ed92eab8cb66b2f552a5015a0668a6bfbc529401d5e5f3cc6904ad81d1bdb59edb0dc9380ece08ad9282ba6be12650fe0f402902938d3ddbc59758e3299368c4123a974b3665c3f94d13d72ee01055635511860b074e03c4028b267160908c2496b3b73593b230d94a99832629c417001ed355359e10ab091441b4a8f8a4332d35e56ac7802eb95070e58c7e9a81c466eca32d7d20bc88191e31282d0c8d0c70a1b2e3ae28c810d95231ee1564e842de4b1c1cb565b99ee0dadd09e668b8808fa7c198c85143f6dd79e1792fe32b5b7196df157a5454a020168e071109c5420456883d9317a80a02162ba1898547c4d9fd2612b124e7f2ac80bb3836f1e3155e425ac0e48048f99821878884662268c43ba09b86588426c42cee2e069e6c593eff0e98d76b630f658d35c918f76b7d36bdee6428cee5314f6b2e2c8c15954ac2844e16e4b8237baa728349f6aaad8843865f92e5f7cf35820fcd434dcc6bbde44d0ae4b9d2532c45d2f8cb97e642d1c483317d85d50d5236030704ffffff000033120100000001");
        byte[] buf = IOUtils.hexStringToByteArray("03ffffff00004b090100000005584fce270100002800000042419e1e45152c236f0000030000030000030000030000030000030000030000030000030000030000030000030000030000030000030000030000030000030000049c03ffffff000008080100000005584fd1af01211004608c1c03ffffff000049090100000005");
        System.out.println("" + buf.length);
        RTMPConnection conn = new RTMPMinaConnection();
        conn.getState().setState(RTMP.STATE_CONNECTED);
        conn.setHandler(this);
        RTMPProtocolDecoder decoder = new RTMPProtocolDecoder();
        decoder.decodeBuffer(conn, IoBuffer.wrap(buf));
    }

    @Test
    public void testNullJsonKV() {
        log.debug("\n testNullJsonKV");
        @SuppressWarnings("unused")
        RTMPProtocolEncoder enc = new RTMPProtocolEncoder();
        RTMPProtocolDecoder dec = new RTMPProtocolDecoder();
        RTMPMinaConnection conn = new RTMPMinaConnection() {
            @Override
            public Encoding getEncoding() {
                return Encoding.AMF3;
            }
        };
        conn.getState().setState(RTMP.STATE_CONNECTED);
        conn.setHandler(this);

        Red5.setConnectionLocal(conn);

        String json = "{Server=NGINX RTMP (github.com/arut/nginx-rtmp-module), width=1280.0, height=720.0, displayWidth=1280.0, displayHeight=720.0, duration=0.0, framerate=30.0, fps=30.0, videodatarate=2500.0, videocodecid=7.0, audiodatarate=160.0, audiocodecid=10.0, profile=, level=}";

        IoBuffer bf = IoBuffer.allocate(128);
        bf.setAutoExpand(true);
        Output writer = new Output(bf);
        String action = "onMetaData";
        writer.writeString(action);
        writer.writeObject(json);
        writer.buf().flip();

        /* using notify event using a Notify object
        Header header = new Header();
        header.setStreamId(1);
        header.setDataType(Notify.TYPE_STREAM_METADATA);
        Notify notify = new Notify(writer.buf());
        notify.setSourceType(Constants.SOURCE_TYPE_LIVE);
        notify.setTimestamp(0);
        notify.setAction(action);
        notify.setHeader(header);

        IoBuffer encoded = enc.encodeStreamMetadata(notify);
        */

        //IoBuffer encoded = writer.buf();

        IoBuffer encoded = IoBuffer.wrap(IOUtils.hexStringToByteArray(
                "05000000000183120100000002000a6f6e4d6574614461746103000653657276657202002e4e47494e582052544d5020286769746875622e636f6d2f617275742f6e67696e782d72746d702d6d6f64756c65290005776964746800409e0000000000000006686569676874004090e00000000000000c646973706c6179576964746800409e000000000000000d646973706c6179486569676874004090e0000000000000086475726174696f6e00000000000000000000096672616d657261746500403e000000000000000366707300403e000000000000000d766964656f64617461726174650040b1940000000000000c766964656f636f646563696400401c000000000000000d617564696f6461746172617465004064000000000000000c617564696f636f6465636964004024000000000000000770726f66696c65020020000000000000000000000000000000000000000000000000000000000000000000056c6576656c0200200000000000000000000000000000000000000000000000000000000000000000000009"));

        byte[] copy = Arrays.copyOfRange(encoded.array(), encoded.arrayOffset(), encoded.remaining());
        log.debug("Encoded: {}", Hex.encodeHexString(copy));

        List<?> objects = dec.decodeBuffer(conn, encoded);
        log.info("Decoded: {}", objects);
        if (objects != null) {
            for (Object object : objects) {
                log.info("Decoded object: {}", object);
            }
        }

        //Notify event = dec.decodePacket(encoded);
        //log.debug("Decoded: {}", event.toString());

        Red5.setConnectionLocal(null);
    }

    @Override
    public void connectionOpened(RTMPConnection conn) {
        log.debug("connectionOpened - conn: {}", conn);
    }

    @Override
    public void messageReceived(RTMPConnection conn, Packet packet) throws Exception {
        log.debug("messageReceived - conn: {} packet: {}", conn, packet);
    }

    @Override
    public void messageSent(RTMPConnection conn, Packet packet) {
        log.debug("messageSent - conn: {} packet: {}", conn, packet);
    }

    @Override
    public void connectionClosed(RTMPConnection conn) {
        log.debug("connectionClosed - conn: {}", conn);
    }

    @SuppressWarnings("unused")
    private void fillBufferFromStringData(IoBuffer buf, String byteDumpFile) throws Exception {
        File f = new File(String.format("%s/target/test-classes/%s", System.getProperty("user.dir"), byteDumpFile));
        BufferedReader in = new BufferedReader(new FileReader(f));
        try {
            String line = null;
            while ((line = in.readLine()) != null) {
                buf.put(IOUtils.hexStringToByteArray(line));
            }
            buf.flip();
            log.debug("Filled buffer: {}", buf);
        } finally {
            in.close();
        }
    }

}
